package main

import (
	"context"
	"log"
	"net/url"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/pion/rtcp"
	"github.com/pion/sdp/v3"
	"github.com/yapingcat/gomedia/mpeg2"

	"gogs.smarteye.com/smarteye/gortc/bvrtc"
	"gogs.smarteye.com/smarteye/gortc/bvrtc/examples/api"
	"gogs.smarteye.com/smarteye/gortc/pkg/description"
	"gogs.smarteye.com/smarteye/gortc/pkg/format"
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

type pcHandle struct {
	fp       *os.File
	fileSize int64
}

func (c *pcHandle) OnPacketRTP(packet *bvrtc.Packet) {
	log.Println(packet.RTP.PayloadType, packet.NTP, packet.PTS, packet.Format.Format().Codec())

	switch packet.Format.Format().(type) {
	case *format.File:
		if data, err := packet.Format.Decode(packet.RTP); err != nil {
			log.Println(err)
		} else {
			if c.fp == nil {
				c.fp, _ = os.Create("out.mp4")
			}

			if c.fp != nil {
				for _, v := range data {
					c.fileSize += int64(len(v))
					_, _ = c.fp.Write(v)
				}
				log.Println(c.fileSize)

				if c.fileSize >= 7770917 {
					_ = packet.Format.SendFileEOF()
				}
			}
		}
	case *format.H264, *format.H265, *format.G711, *format.G726:
		if data, err := packet.Format.Decode(packet.RTP); err != nil {
			log.Println(err)
		} else {
			for _, v := range data {
				log.Println(len(v))
			}
		}

	case *format.PS:
		err := packet.Format.DecodePS(packet.RTP, func(data []byte, cid mpeg2.PS_STREAM_TYPE, pts time.Duration) {
			log.Println(len(data), cid, pts)
		})
		if err != nil {
			log.Println(err)
		}

	default:
		log.Println("unknown format", packet.Format.Format())
	}

}

func (c *pcHandle) OnPacketRTCP(packet *rtcp.Header, raw []byte) {
	log.Println("receive RTCP: ", packet.Type.String())
}

func (c *pcHandle) OnPacketLost(err error) {
	log.Println(err)
}

func (c *pcHandle) OnDecodeError(err error) {
	log.Println(err)
}

func (c *pcHandle) OnSessionError(err error) {
	log.Println(err)
}

func main() {
	sapi := api.NewAPI(api.ClientConfig{
		Scheme:   "http",
		Host:     "192.168.88.11",
		Port:     9780,
		Username: "admin",
		Password: "123456",
	})
	if err := sapi.Login(); err != nil {
		log.Println(err)
		return
	}

	peerConnection := bvrtc.NewPeerConnection(&pcHandle{})

	// 创建 Offer
	uri, _ := url.Parse("L3N0b3JhZ2UvZW11bGF0ZWQvMC9NQ1UvVmlkZW8vUFVfMjA1QzA2RkZfMDBfMjAyNDA5MDZfMTA0MjMxX0xBMDgwMC5tcDQ")
	offer, err := peerConnection.CreateOffer(&description.Session{
		URI: uri,
		TimeDescriptions: []sdp.TimeDescription{
			{
				Timing: sdp.Timing{
					StartTime: 0,
					StopTime:  0,
				},
			},
		},
		Medias: []*description.Media{
			{
				Type:        description.MediaTypeApplication,
				ID:          "22",
				Direction:   sdp.DirectionRecvOnly,
				SSRC:        111,
				CName:       "uct",
				StreamLabel: "40615a81a567c722",
				Label:       "file0",
				Protos:      []string{"TCP", "RTP", "AVP"},
				Formats: []format.Format{
					&format.File{
						PayloadTyp: 98,
					},
				},
			},
		},
	})
	if err != nil {
		log.Println(err)
		return
	}

	// 设置本地SDP
	peerConnection.SetLocalDescription(offer)
	bytesOffer, err := offer.MarshalBytes()
	if err != nil {
		log.Println(err)
		return
	}

	// 打开通道
	if dialogId, bytesAnswer, err := sapi.OpenDialog("UA_205C06FF", 0x010210, bytesOffer); err != nil {
		log.Println(err)
		return
	} else {
		log.Printf("发送SDP: \n%v", string(bytesOffer))
		log.Printf("接收SDP: \n%v", string(bytesAnswer))
		_ = dialogId

		var answer description.Session
		_ = answer.UnmarshalBytes(bytesAnswer)

		// 设置远程SDP
		peerConnection.SetRemoteDescription(&answer)
	}

	// 创建解码器(不创建解码器, 收到rtp包后无法解码)
	peerConnection.RangeRemoteFormat(func(media *bvrtc.Media, clientFormat *bvrtc.Format) {
		if !media.HaveSender() {
			// 远端没有数据发送者, 即: 这个media接收不到数据, 不需要创建解码器
			return
		}
		_ = clientFormat.CreateDecoder()
	})

	// 开始传输
	_ = peerConnection.Start()

	defer peerConnection.Close()

	ctx, cancel := signal.NotifyContext(context.TODO(), syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
	defer cancel()

	<-ctx.Done()
}
